package webServer;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class Server extends Thread {
	private int port;
	private ServerSocket serverSocket;

	public Server(int port) {
		this.port = port;
		this.start();
	}
	/**
	 * Prints out a String
	 * @param stringToPrint String you want to print
	 */
	private void print(String stringToPrint) {
		System.out.println(stringToPrint);
	}
	/**
	 * Starts the programm
	 * listens to a socket. if there is a request handle it. HTTP/1.0
	 */
	public void run() {
		try {
			print("Trying to bind to localhost on port " + port + "...");
			serverSocket = new ServerSocket(port);
		} catch (Exception e) {
			print("Fatal Error:" + e.getMessage());
			return;
		}
		print("OK!");
		while (true) {
			print("Ready, Waiting for requests...");
			try {
				Socket connectionsocket = serverSocket.accept();
				InetAddress client = connectionsocket.getInetAddress();
				print(client.getHostName() + " connected to server");
				BufferedReader input = new BufferedReader(
						new InputStreamReader(connectionsocket.getInputStream()));
				// Prepare a outputstream from us to the client, this will be
				// used sending back our response
				DataOutputStream output = new DataOutputStream(
						connectionsocket.getOutputStream());
				http_handler(input, output);
			} catch (Exception e) {
				print("Error:" + e.getMessage());
			}
		}
	}
	/**
	 * Handeles the http request
	 * @param input the request
	 * @param output needed to send our response
	 */
	private void http_handler(BufferedReader input, DataOutputStream output) {
		int method = 0; // 1 get, 2 head, 0 not supported
		String path = null;
		try {
			String request = input.readLine();
			path = getPath(request);
			request.toUpperCase();
			if (request.startsWith("GET")) {
				method = 1;
			}else if (request.startsWith("HEAD")) {
				method = 2;
			}
			if (method == 0) {
				try {
					output.writeBytes(construct_http_header(501, 0));
					output.close();
					return;
				} catch (Exception e2) {
					print("error:" + e2.getMessage());
				}
			}
		} catch (Exception e) {
			print("error:" + e.getMessage());
		}
		print("Client requested:" + new File(path).getAbsolutePath());
		FileInputStream requestedfile = null;
		try {
			requestedfile = new FileInputStream(path);
		} catch (Exception e) {
			try {
				// if file does not exists, give 404
				output.writeBytes(construct_http_header(404, 0));
				output.close();
			} catch (Exception e3) {
				print("error:" + e3.getMessage());
			}
			print("error:" + e.getMessage());
		}

		try {
			int type = getType( path );
			output.writeBytes(construct_http_header(200, type));
			// if GET, send body too
			if (method == 1) {
				while (true) {
					int b = requestedfile.read();
					if (b == -1) {
						break;
					}
					output.write(b);
				}
			}
			output.close();
			requestedfile.close();
		} catch (Exception e) {
		}

	}
	/**
	 * get filetype
	 * @param path path of the file
	 * @return a pathtype
	 */
	private int getType( String path) {
		int typeIs = 0;
		if (path.endsWith(".zip")) {
			typeIs = 3;
		}
		if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
			typeIs = 1;
		}
		if (path.endsWith(".gif")) {
			typeIs = 2;
		}
		if (path.endsWith(".html") || path.endsWith(".htm")) {
			typeIs = 5;
		}
		return typeIs;
	}
	/**
	 * get the path of the file you want to send back
	 * @param request the request
	 * @return the path of the file in the filesystem
	 */
	private String getPath(String request) {
		String path = null;
		// request contains "GET /index.html HTTP/1.0 ..."
		String[] requestArray = request.split(" ");
		System.out.println( "path: " + requestArray[1].substring( 1 ) );
		path = requestArray[1].substring( 1 ); 
		return path;
	}
	/**
	 * Constructs the http header that is going back with the response
	 * @param statusCode statuscode the header needs
	 * @param fileType type of the file
	 * @return a http header
	 */
	private String construct_http_header(int statusCode, int fileType) {
		String httpHeader = "HTTP/1.0 ";
		httpHeader = httpHeader + getStatuscode( statusCode );
		httpHeader = httpHeader + "\r\n"; // other header fields,
		httpHeader = httpHeader + "Connection: close\r\n";
		httpHeader = httpHeader + "Server: JaroonKennyServer\r\n";
		httpHeader = httpHeader + getFileType( fileType );
		httpHeader = httpHeader + "\r\n"; // end of header
		return httpHeader;
	}
	/**
	 * get the filetype
	 * @param fileType int filetype
	 * @return a filetype string for the header
	 */
	private String getFileType(int fileType) {
		switch (fileType) {
		case 0:
			return "";
		case 1:
			return "Content-Type: image/jpeg\r\n";
		case 2:
			return "Content-Type: image/gif\r\n";
		default:
			return "Content-Type: text/html\r\n";
		}
	}
	/**
	 * get a kind of statuscode
	 * @param statusCode the statuscode you want
	 * @return a statuscode
	 */
	private String getStatuscode(int statusCode) {
		switch (statusCode) {
		case 200:
			return "200 OK";
		case 400:
			return "400 Bad Request"; // unused
		case 403:
			return "403 Forbidden"; // unused
		case 404:
			return "404 Not Found";
		case 500:
			return "500 Internal Server Error"; // unused
		case 501:
			return "501 Not Implemented";
		default:
			return "500 Internal Server Error";
		}
	}

}